import uno
import requests
import json

# Ollama API配置
OLLAMA_API_URL = "http://localhost:9090/api/generate"
OLLAMA_MODEL = "hybrid-8B-ds"  # 替换为你的Ollama模型名称

def call_ollama_api(prompt):
    """调用Ollama API，获取生成的文本"""
    data = {
        "model": OLLAMA_MODEL,
        "prompt": prompt,
        "stream": False  # 设置为False以获取完整响应
    }
    try:
        response = requests.post(OLLAMA_API_URL, json=data)
        if response.status_code == 200:
            return response.json()["response"], response.status_code, None
        else:
            return None, response.status_code, response.text
    except Exception as e:
        return None, None, str(e)

def process_ai_response(ai_response):
    """处理AI返回的内容，提取Slide标题和内容"""
    slides = []
    sections = ai_response.split('---')  # 以'---'分隔幻灯片

    for section in sections:
        section = section.strip()  # 去除前后空白
        if not section:
            continue  # 跳过空段落

        # 提取标题和内容
        lines = section.split('\n')
        title = None
        content = []
        for line in lines:
            line = line.strip()
            if line.startswith('### '):
                title = line[4:].strip()  # 提取标题（###）
            else:
                content.append(line)  # 提取内容
        if title:
            slides.append({"title": title, "content": "\n".join(content)})

    return slides


def create_ppt_test(ai_response):
     desktop = XSCRIPTCONTEXT.getDesktop()
     doc = desktop.loadComponentFromURL("private:factory/simpress", "_blank", 0, ())

     # 获取文档的幻灯片集合
     draw_pages = doc.getDrawPages()

     # 获取第一张幻灯片的布局名称
     first_slide = draw_pages.getByIndex(0)
     layout_name = first_slide.getPropertyValue("Layout")  # 修正多余的括号
     slides = process_ai_response(ai_response)
     # for i in range(10):
     for i, slide_data in enumerate(slides):
        if i == 0:
            # 第一张幻灯片已经存在，直接使用
            current_slide = first_slide
        else:
            # 从第二张幻灯片开始，使用与第一张幻灯片相同的布局
            current_slide = draw_pages.insertNewByIndex(i)
            current_slide.setPropertyValue("Layout", layout_name)  # 设置布局

        # 找到第一个文本框（标题）
        title_box = None
        # 找到第二个文本框（内容）
        content_box = None

        # 遍历幻灯片中的形状
        for shape in current_slide:
            if shape.supportsService("com.sun.star.drawing.TextShape"):
                if title_box is None:
                    title_box = shape  # 第一个文本框
                else:
                    content_box = shape  # 第二个文本框
                    break  # 找到两个文本框后退出循环

        # 填充第一个文本框（标题）
        if title_box is not None:
            title_box.String = slide_data['title']

        # 填充第二个文本框（内容）
        if content_box is not None:
            content_box.String = slide_data['content']
            # content_box.setPropertyValue("ParaAdjust",TextAlign.LEFT)
            # paragraphs = content_box.Text.createEnumeration()
            # while paragraphs.hasMoreElements():
            #   paragraph=paragraphs.nextElement()
            #   # content_box.Text.HoriAdjust = uno.getConstantByName("com.sun.star.drawing.TextHorizontalAdjust.LEFT")
            #   paragraph.ParaAdjust = uno.getConstantByName("com.sun.star.style.ParagraphAdjust_LEFT")
            #   # paragraph.setPropertyValue("ParaAdjust",TextAlign_LEFT)
           
     return impress_doc,len(slides)

def create_ppt_from_ai_response(ai_response):
    """根据AI生成的内容创建PPT"""
    try:
        # 获取当前组件上下文
        # ctx = uno.getComponentContext()
        # desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        desktop = XSCRIPTCONTENT.getDesktop()

        # 创建一个新的Impress文档
        impress_doc = desktop.loadComponentFromURL("private:factory/simpress", "_blank", 0, ())

        # 获取文档的幻灯片集合
        draw_pages = impress_doc.getDrawPages()

        # 获取第一张幻灯片的布局名称
        first_slide = draw_pages.getByIndex(0)
        layout_name = first_slide.getPropertyValue("Layout")  # 获取布局名称

        # 处理AI返回的内容
        slides = process_ai_response(ai_response)

        # 循环创建幻灯片并填充内容
        for i, slide_data in enumerate(slides):
            if i == 0:
                # 第一张幻灯片已经存在，直接使用
                current_slide = first_slide
            else:
                # 从第二张幻灯片开始，插入新的幻灯片，并指定布局
                current_slide = draw_pages.insertNewByIndex(i)
                current_slide.setPropertyValue("Layout",layout_name)  # 使用第一张幻灯片的布局

            # 找到第一个文本框（标题）
            title_box = None
            # 找到第二个文本框（内容）
            content_box = None

            # 遍历幻灯片中的形状
            for shape in current_slide:
                if shape.supportsService("com.sun.star.drawing.TextShape"):
                    if title_box is None:
                        title_box = shape  # 第一个文本框
                    else:
                        content_box = shape  # 第二个文本框
                        break  # 找到两个文本框后退出循环

            # 填充第一个文本框（标题）
            if title_box is not None:
                # title_box.String = slide_data["title"]
                title_box.String = f"Slide {i+1}"

            # 填充第二个文本框（内容）并设置为左对齐
            if content_box is not None:
                # content_box.String = slide_data["content"]
                content_box.String = f"Content: {i+1}"
                # 设置内容文本框为左对齐
                content_box.Text.HoriAdjust = uno.getConstantByName("com.sun.star.drawing.TextHorizontalAdjust.LEFT")

        # 返回Impress文档对象和幻灯片数量，以便后续操作
        return impress_doc, len(slides)
    except Exception as e:
        raise Exception(f"创建PPT失败: {e}")

def insert_log_to_doc(doc, log_text):
    """将日志插入到当前文档中"""
    try:
        cursor = doc.Text.createTextCursor()
        cursor.gotoEnd(False)
        doc.Text.insertString(cursor, "\n" + log_text + "\n", False)
    except Exception as e:
        raise Exception(f"插入日志失败: {e}")

def ollama_ppt_demo(*args):
    """主函数：与Ollama API互动并生成PPT"""
    try:
        # 获取当前文档（Writer文档）
        # ctx = uno.getComponentContext()
        # doc1 = XSCRIPTCONTEXT if len(args) == 0 else args[0]
        # ctx = doc1.getDocument()

        ctx = None
        if len(args) > 0 and hasattr(args[0], "getDocument"):
            ctx = args[0]
        else:
            ctx = uno.getComponentContext()

        desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        writer_doc = desktop.getCurrentComponent()

        # 检查文档是否支持文本提取
        if not hasattr(writer_doc, "Text"):
            raise Exception("当前文档不支持文本提取！")

        # 提取前100个字符（如果不足100个字符，则提取全部）
        text = writer_doc.Text.getString()
        prompt = text[:100] if len(text) >= 100 else text
        if not prompt:
            raise Exception("文档内容为空！")

        # 调用Ollama API
        print("正在与Ollama API交互...")
        ollama_response, status_code, error = call_ollama_api(prompt)

        # 如果Ollama生成成功，生成PPT
        if ollama_response:
            print("正在生成PPT...")
            # impress_doc, slide_count = create_ppt_from_ai_response(ollama_response)
            impress_doc, slide_count = create_ppt_test(ollama_response)
            print("PPT生成完成！")
            # 调试处理ai返回的slides数量
            # slides = process_ai_response(ollama_response)
            # slide_count = len(slides)

            # 切换回Writer文档
            desktop.setCurrentComponent(writer_doc)

            # 记录日志
            log_text = f"=== 日志 ===\n"
            log_text += f"截取的文档内容: {prompt}\n"
            log_text += f"API请求状态码: {status_code}\n"
            log_text += f"Ollama生成内容: {ollama_response}\n"
            log_text += f"提取的幻灯片数量: {slide_count}\n"  # 添加幻灯片数量信息
            # for i, slide_data in enumerate(slides):
            #     log_text += f"slide:{i} \n title: {slide_data['title']} \n"

            # 将日志插入到Writer文档中
            insert_log_to_doc(writer_doc, log_text)
        else:
            # 记录API请求失败的日志
            log_text = f"=== 日志 ===\n"
            log_text += f"截取的文档内容: {prompt}\n"
            log_text += f"API请求状态码: {status_code}\n"
            log_text += f"API请求失败: {error}\n"
            insert_log_to_doc(writer_doc, log_text)
    except Exception as e:
        print(f"发生错误: {e}")

# 将函数导出为宏
g_exportedScripts = (ollama_ppt_demo,)

